package cn.tedu.ceb.collection.service.impl;

import cn.tedu.ceb.bean.CollectionDetail;
import cn.tedu.ceb.bean.Result;
import cn.tedu.ceb.collection.mapper.CollectionMapper;
import cn.tedu.ceb.collection.pojo.entity.Collection;
import cn.tedu.ceb.collection.service.CollectionService;
import cn.tedu.ceb.positions.mapper.PositionsMapper;
import cn.tedu.ceb.positions.pojo.Positions;
import cn.tedu.ceb.user.mapper.UserMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class CollectionServiceImpl implements CollectionService {

    @Autowired
    private PositionsMapper positionsMapper;
    @Autowired
    private CollectionMapper collectionMapper;

    @Autowired
    private UserMapper userMapper;

    // 用户-职位收藏关系矩阵
    private int[][] matrix;
    /**
     * 查询用户是否收藏该岗位
     * @param uid
     * @param pid
     * @return
     */
    @Override
    public Result findCollection(Integer uid, Integer pid) {
        Integer uidAndPid = positionsMapper.findCollectUidAndPid(uid, pid);
        if (uidAndPid == 0 ){
            return new Result(false,"没有收藏");
        }
        return new Result(true,"已收藏");
    }

    @Override
    public void addCollection(Integer uid, Integer pid) {
        Positions positions = positionsMapper.selectById(pid);
        positionsMapper.addCollection(uid,pid,positions.getPFlag());
    }

    @Override
    public void deleteCollection(Integer uid, Integer pid) {
        QueryWrapper<Collection> wrapper = new QueryWrapper<>();
        wrapper.eq("id",pid);
        wrapper.eq("user_id",uid);
        collectionMapper.delete(wrapper);

    }

    @Override
    public List<CollectionDetail> showAllCollection(Integer uid, Integer page, Integer size) {
        QueryWrapper<Collection> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",uid);
        List<Collection> list = collectionMapper.selectList(queryWrapper);

        List<CollectionDetail> detailList = new ArrayList<>();
        Integer count = Math.toIntExact(collectionMapper.selectCount(queryWrapper));
        for (Collection temp : list) {
            Positions p = positionsMapper.selectByPrimaryKey(temp.getPId());
            CollectionDetail col = new CollectionDetail(temp.getId(),count,p.getPName(),p.getPClassify(),p.getPDescribe(),p.getPResponsibility()
                    , p.getPRequest(),p.getPWorkSite(),p.getPDepartment(),p.getPFlag());
            detailList.add(col);
        }

        return detailList;
    }

    /**
     * 给用户推荐职位
     *
     * @param uid 用户ID
     * @param k   需要推荐的职位数量
     * @return 返回一个Result对象，其中包含推荐结果的状态、消息和推荐的职位列表
     */
    @Override
    public Result recommendKPosition(Integer uid, Integer k) {
        initMatrix(); // 初始化用户-职位评分矩阵
        List<Integer> list = recommend(uid, k); // 为指定用户推荐职位ID列表
        List<Positions> positions = positionsMapper.selectBatchIds(list); // 根据职位ID列表查询职位详情
        return new Result(true, "推荐成功", positions); // 创建并返回推荐结果
    }

// 推荐算法实现

    /**
     * similarity方法通过余弦相似度计算职位之间的相似度
     *
     * @param p1 第一个职位的ID
     * @param p2 第二个职位的ID
     * @return 相似度值
     */
    private double similarity(int p1, int p2) {
        int sum1 = 0, sum2 = 0, sum3 = 0; // 初始化累加变量
        for (int i = 0; i < matrix.length; i++) { // 遍历每个用户
            if (matrix[i][p1] > 0 && matrix[i][p2] > 0) { // 如果两个职位都被同一个用户标记过
                sum1 += matrix[i][p1] * matrix[i][p2]; // 计算分子部分
                sum2 += matrix[i][p1] * matrix[i][p1]; // 计算第一个职位的分母部分
                sum3 += matrix[i][p2] * matrix[i][p2]; // 计算第二个职位的分母部分
            }
        }
        double sim = sum1 / (Math.sqrt(sum2) * Math.sqrt(sum3)); // 计算余弦相似度
        return sim; // 返回相似度值
    }

    /**
     * recommend方法根据用户的收藏情况和职位之间的相似度计算推荐得分，并返回前k个得分最高的职位
     *
     * @param userId 用户ID
     * @param k      推荐的职位数量
     * @return 推荐的职位ID列表
     */
    private List<Integer> recommend(int userId, int k) {
        List<Integer> items = new ArrayList<>(); // 创建职位ID列表
        Map<Integer, Double> scores = new HashMap<>(); // 创建Map存储每个未被收藏过的职位及其推荐得分
        for (int i = 1; i < matrix[1].length; i++) { // 遍历所有职位
            if (matrix[userId][i] == 0) { // 如果用户没有收藏过该职位
                double score = 0; // 初始化得分
                for (int j = 1; j < matrix[1].length; j++) { // 再次遍历所有职位
                    if (matrix[userId][j] > 0) { // 如果用户收藏过另一个职位
                        double sim = similarity(i, j); // 计算未被收藏的职位与已收藏职位的相似度
                        score += sim * matrix[userId][j]; // 更新得分
                    }
                }
                scores.put(i, score); // 将职位ID和得分添加到Map中
            }
        }

        // 对推荐职位按照得分进行排序
        List<Map.Entry<Integer, Double>> sortedList = new ArrayList<>(scores.entrySet()); // 将Map转换为Entry列表
        Collections.sort(sortedList, new Comparator<Map.Entry<Integer, Double>>() { // 定义比较器进行排序
            @Override
            public int compare(Map.Entry<Integer, Double> o1, Map.Entry<Integer, Double> o2) {
                return o2.getValue().compareTo(o1.getValue()); // 按照得分降序排列
            }
        });

        // 返回前k个得分最高的职位
        for (int i = 0; i < k; i++) { // 遍历前k个条目
            items.add(sortedList.get(i).getKey()); // 添加得分最高的职位ID到列表
        }
        return items; // 返回最终的职位ID列表
    }

    /**
     * 初始化用户-职位评分矩阵
     */
    private void initMatrix() {
        QueryWrapper<Positions> wrapper = new QueryWrapper<>(); // 创建QueryWrapper实例
        wrapper.select("max(id) as id"); // 设置查询条件，选择最大的职位ID
        Positions maxPosition = positionsMapper.selectOne(wrapper); // 查询最大的职位ID
        System.out.println("最大职位ID：" + maxPosition); // 打印最大职位ID信息
        matrix = new int[userMapper.showUserCount() + 1][maxPosition.getId() + 1]; // 初始化矩阵
        for (int i = 0; i < matrix.length; i++) { // 遍历每一行
            Arrays.fill(matrix[i], 0); // 将矩阵中的元素全部初始化为0
        }
        List<Collection> collections = collectionMapper.selectList(null); // 查询所有收藏记录
        for (Collection collection : collections) { // 遍历收藏记录
            matrix[collection.getUserId()][collection.getPId()] = 1; // 在矩阵中标记用户收藏的职位
        }
    }
}
